package com.tedu.submarine;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

public class World extends JPanel {
    //窗口的宽度
    public static final int WIDTH = 641;
    //窗口的高度
    public static final int HEIGHT = 479;

    /**运行状态*/
    public static final int RUNNING = 0;

    /**暂停状态*/
    public static final int PAUSE = 1;

    /**
     * 游戏结束状态
     */
    public static final int GAME_OVER = 2;
    private int state = RUNNING;//当前状态 默认为运行状态


    //创建窗口中看到的对象
    private BattleShip ship = new BattleShip();//战舰对象
    private SeaObject[] submarines = {};  //潜艇数组
    private Mine[] mines = {};//水雷数组
    private Bomb[] bombs = {};//炸弹数组

    /**
     * 生成潜艇(侦查潜艇 鱼雷潜艇 水雷潜艇)对象
     * @return  返回潜艇
     */
    private SeaObject nextSubmarine(){
        Random random = new Random();//创建随机数对象
        int type = random.nextInt(20);//0到19之间
        if(type < 10){ //0到9时 返回侦查潜艇对象
            return new ObserveSubmarine();
        }else if(type < 16 ){ // 10 到 15 时 返回鱼雷潜艇对象
            return new TorpedoSubmarine();
        }else{ //16 到 19时 返回水雷潜艇对象
            return new MineSubmarine();
        }
    }

    private int subEnterIndex = 0; //潜艇入场计时

    /**
     * 潜艇入场
     */
    private void submarineEnterAction(){
        subEnterIndex++;//每10毫秒增1
        if(subEnterIndex % 40 == 0){ //每400(40*10)毫秒走一次
            SeaObject obj = nextSubmarine(); //获取潜艇对象
            submarines = Arrays.copyOf(submarines,submarines.length+1);//扩容
            submarines[submarines.length-1] = obj; // 将obj添加到submarines最后一个元素上
        }
    }

    private int mineEnterIndex = 0;//水雷入场计数

    /**
     * 水雷入场
     */
    private void mineEnterAction(){//每10毫秒走一次
        mineEnterIndex++; //每10毫秒增1
        if(mineEnterIndex%100==0){ //每1000(100*10)毫秒走一次
            for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
                if(submarines[i] instanceof MineSubmarine){ //若潜艇为水雷潜艇
                    MineSubmarine ms = (MineSubmarine)submarines[i]; //将潜艇转换为水雷潜艇类型
                    Mine obj = ms.shootMine(); //获取水雷对象
                    mines = Arrays.copyOf(mines,mines.length+1); //扩容
                    mines[mines.length-1] = obj; //将obj添加到mines最后一个元素上
                }
            }
        }

    }

    /**
     * 海洋对象移动
     */
    private void moveAction(){ //每10毫秒走一次
        for (int i = 0; i < submarines.length; i++) { //遍历所有潜艇
            submarines[i].move();//潜艇移动
        }
        for (int i = 0; i < mines.length; i++) { //遍历所有水雷
            mines[i].move();//水雷移动
        }
        for (int i = 0; i < bombs.length; i++) {//遍历所有炸弹
            bombs[i].move();//炸弹移动
        }



    }

    /**
     * 启动程序的运行
     *
     */
    private void action(){
        KeyAdapter keyAdapter = new KeyAdapter(){  // 当按键抬起时会自动触发
            @Override
            public void keyReleased(KeyEvent e) {

                //如果按下的是P键
                if(e.getKeyCode() == KeyEvent.VK_P){
                    if(state == RUNNING){ //运行状态修改为暂停状态
                        state = PAUSE;
                    }else if(state == PAUSE){ //暂停状态 修改为运行状态
                        state = RUNNING;
                    }
                }
                //如果运行 按下的是VK_SPACE
                if(state == RUNNING){
                    if(e.getKeyCode() == KeyEvent.VK_SPACE){
                        Bomb obj = ship.shootBomb();//获取炸弹对象
                        bombs = Arrays.copyOf(bombs, bombs.length+1);//扩容+1
                        bombs[bombs.length-1] = obj;//将obj添加到最后的一个元素
                    }
                    //如果按下的左移键盘
                    if(e.getKeyCode() == KeyEvent.VK_LEFT){
                        ship.moveLeft();//战舰左移动
                    }
                    //如果按下的是右移键盘
                    if(e.getKeyCode() == KeyEvent.VK_RIGHT){
                        ship.moveRight();//战舰右移动
                    }
                }
            }
        };
        this.addKeyListener(keyAdapter);//添加按键监听事件

        Timer timer = new Timer();//定时器对象
        int interval = 10;//定时间隔(以毫秒为单位)
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if(state == RUNNING){//如果在运行状态下
                    submarineEnterAction();//潜艇入场
                    mineEnterAction();//水雷入场
                    moveAction();//海洋对象移动
                    outOfBoundsAction();//删除越界的海洋对象
                    bombBangAction();//炸弹与潜艇的碰撞
                    mineBangAction();//水雷和战舰碰撞
                    checkGameOverAction();//检查游戏结束
                    repaint(); //重画 ---系统自动调用paint()方法
                }

            }
        }, interval, interval);//定时计划表
    }

    /**
     * 检查游戏结束
     */
    private void checkGameOverAction() {
        if(ship.getLife() <= 0){//若战舰的命数<=0 表示游戏结束
            state = GAME_OVER;//将状态改为游戏结束
        }
    }

    /**
     * 水雷与战舰的碰撞
     */
    private void mineBangAction() {
        /**
         * 遍历所有水雷
         */
        for (int i = 0; i < mines.length; i++) {
            Mine m = mines[i];
            if(m.isLive() && ship.isLive() && m.isHit(ship)){//撞上
                m.goDead();//水雷去死
                ship.subtractLife();//战舰减命
            }
        }
    }

    /**
     * 玩家得分
     */
    private int score = 0;

    /**
     * 炸弹与潜艇的碰撞
     */
    private void bombBangAction() {
        /**
         * 遍历所有的炸弹
         */
        for (int i = 0; i < bombs.length; i++) {
            /**
             * 获取每一个炸弹
             */
            Bomb bomb = bombs[i];
            /**
             * 遍历所有的潜艇
             */
            for (int j = 0; j < submarines.length; j++) {
                /**
                 * 获取每一个潜艇
                 */
                SeaObject s = submarines[j];
                /**
                 * 若都活着 并且碰上
                 * 让炸弹去死
                 * 让潜艇去死
                 */
                if(bomb.isLive() && s.isLive() && bomb.isHit(s)){

                    s.goDead();
                    bomb.goDead();
                    /**
                     * 如果打中的是得分潜艇
                     * 写玩家得分
                     */
                    if(s instanceof EnemyScore){
                        EnemyScore es = (EnemyScore) s;
                        score += es.getScore();
                    }
                    /**
                     * 如果打中的是得命 潜艇
                     *  玩家得命
                     */
                    if(s instanceof EnemyLife){
                        EnemyLife el = (EnemyLife) s;
                        int num = el.getLife();//获取命数
                        ship.addLife(num);//战舰得命
                    }
                }
            }
        }
    }

    /**
     * 删除越界的海洋对象
     * 主要目的：避免内存泄漏
     */
    private void outOfBoundsAction() {
        /**
         * 遍历所有的潜艇
         */
        for (int i = 0; i < submarines.length; i++) {
            /**
             * 判断潜艇是否越界 以及潜艇 是否死了
             */
            if (submarines[i].isOutOfBounds() || submarines[i].isDead() ) {
                /**
                 * 将越界元素替换为最后的一个元素
                 */
                submarines[i] = submarines[submarines.length - 1];//
                /**
                 * 减少数组元素
                 */
                submarines = Arrays.copyOf(submarines, submarines.length-1);
            }
        }
        /**
        * 遍历所有水雷
        * */
        for (int i = 0; i < mines.length; i++) {
            /**
             * 判断水雷是否越界  或者 水雷是否死亡
             */
            if(mines[i].isOutOfBounds() || mines[i].isDead() ){
                /**
                 * 将越界的元素 替换成最后的一个元素
                 * */
                mines[i] = mines[mines.length - 1];
                /**
                * 减少数组元素
                * */
                mines = Arrays.copyOf(mines, mines.length-1);
            }
        }

        /**
         * 遍历所有炸弹
         */
        for (int i = 0; i < bombs.length; i++) {
            /**
             * 判断所有炸弹是否越界 或者 死亡
             */
            if(bombs[i].isOutOfBounds() || bombs[i].isDead()){
                /**
                 * 将越界的炸弹替换成最后一个元素
                 */
                bombs[i] = bombs[bombs.length-1];
                /**
                 * 缩小数组
                 */
                bombs = Arrays.copyOf(bombs, bombs.length-1);
            }
        }
    }

    /**
     * 重写paint()画
     * @param g 系统自带的画笔
     */
    public void paint(Graphics g){ //每10毫秒走一次
        Images.sea.paintIcon(null,g,0,0); //画海洋图---不要求掌握
        ship.paintImage(g); //画战舰
        for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
            submarines[i].paintImage(g); //画潜艇
        }
        for(int i=0;i<mines.length;i++){ //遍历所有水雷
            mines[i].paintImage(g); //画水雷
        }
        for(int i=0;i<bombs.length;i++){ //遍历所有炸弹
            bombs[i].paintImage(g); //画炸弹
        }

        g.drawString("SCORE: "+score, 200, 50); //画分
        g.drawString("LIFE: "+ship.getLife(), 400, 50);//画命

        if(state == GAME_OVER){
            Images.gameover.paintIcon(null, g, 0, 0);
        }

    }


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        //创建面板上的所有对象
        World world = new World();
        //设置回去焦点
        world.setFocusable(true);
        //在窗体上添加面板
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH+16, HEIGHT+40);
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);//自动调用paint()方法


        world.action();//启动程序执行
    }

}
